﻿using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Xml;
using System.Collections.Generic;

namespace TeleTwitter.Lib 
{
    public class PownceManager
    {
        #region Settings

        static PownceManager()
        {
            _version = typeof(PownceManager).Assembly.GetName().Version;
        }

        public static void SetClientAppDetails(string name, string link, Version ver)
        {
            _clientName = name;
            _clientLink = link;
            _version = ver;
        }

        #endregion

        #region Private Members

        private static string _password = string.Empty;
        private static string _username = string.Empty;
        private User _currentUser = null;

        // NOTE: all API URLs should use param 0 for the file type (i.e. - xml or json)
        // The SendRequest method will format the URL strings with param 0 as the selected API file extension
        // and param 1 as the "command"
        //private const string ANOTHER_FRIENDS_TIMELINE_URL = "http://twitter.com/statuses/friends_timeline/{1}.{0}";
        //private const string FRIENDS_TIMELINE_URL = "http://twitter.com/statuses/friends_timeline.{0}";
        //private const string PUBLIC_TIMELINE_URL = "http://twitter.com/statuses/public_timeline.{0}";
        //private const string UPDATE_STATUS_URL = "http://twitter.com/statuses/update.{0}?status={1}";
        //private const string USER_URL = "http://twitter.com/users/show/{1}.{0}";

        private static string _clientName = "TeleTwitter";
        private static string _clientLink = "http://www.teletwitter.com";
        private static Version _version = null;
        private static PownceManager _pownceManager;

        #endregion

        #region Constructor(s)

        private PownceManager(string username, string password)
        {
            _username = username;
            _password = password;
            //LoadCurrentUser();
        }

        private PownceManager()
        {
        }

        #endregion

        #region Methods

        public static PownceManager Instance()
        {
            if (_pownceManager == null)
            {
               _pownceManager = new PownceManager();
            }
            if (_pownceManager.Username != string.Empty && _pownceManager.Password != string.Empty)
            {
               //_pownceManager.LoadCurrentUser();
            }
            return _pownceManager;
        }

        private static string CreatePownceNonce()
        {
           string timeval = DateTime.Now.Ticks.ToString();
           UTF8Encoding encoding = new UTF8Encoding();
           byte[] bytes = encoding.GetBytes(timeval);
           return Convert.ToBase64String(bytes);
        }

        private static string GetPownceDigest(string pownceToken, string pownceNonce, string timestamp)
        {
           //return Base64(SHA1(pownceNonce + timestamp + pownceToken));
           string toEncode = pownceNonce + timestamp + pownceToken;
           Encoding encoder = new UTF8Encoding();
           SHA1 sha = new SHA1Managed();
           byte[] passwordHash = sha.ComputeHash(encoder.GetBytes(toEncode));
           return Convert.ToBase64String(passwordHash);
        }

        private string GetPownceAuthString(string pownceDigest, string pownceNonce, string timestamp)
        {
           return "UsernameToken Username=\"" + Username + "\", PasswordDigest=\"" + pownceDigest + "\", Nonce=\"" + pownceNonce + "\", Created=\"" + timestamp + "\"";
        }

        private static string GetPownceTimestamp()
        {
           //DateFormat to look like 2007-07-16T19:54:21Z
           string timestamp = DateTime.Now.ToString("yyyy-MM-dd") + "T" + DateTime.Now.ToString("HH:mm:ss") + "Z";
           return timestamp;
        }

         private static string GetPownceToken(string username, string password)
         {
            string pownceLoginPath = "http://pownce.com/api/login/";

            string token = string.Empty;

            string result = string.Empty;
            HttpWebRequest webRequest = null;
            WebResponse webResponse = null;
            try {
               webRequest = (HttpWebRequest)WebRequest.Create(pownceLoginPath);
               webRequest.Method = "GET";
               webRequest.ServicePoint.Expect100Continue = false;
               webRequest.KeepAlive = false;
               webRequest.Credentials = GetCredentials(username, password);               
               webRequest.ContentType = "application/x-www-urlencoded";
               webRequest.Accept = "application/xml";

               webResponse = webRequest.GetResponse();

               using (StreamReader streamReader = new StreamReader(webResponse.GetResponseStream())) {
                  result = streamReader.ReadToEnd();
                  streamReader.Close();
               }
            } catch (WebException webException) {
               throw webException;
            } catch (Exception exception) {
               throw exception;
            } finally {
               try {
                  if (webRequest != null) {
                     webRequest.GetRequestStream().Close();
                  }
                  if (webResponse != null) {
                     webResponse.GetResponseStream().Close();
                  }
               } catch {

               }
            }

            XmlDocument document = new XmlDocument();
            document.LoadXml(result);
            XmlElement el = document.DocumentElement;
            token = el.GetAttribute("token");

            return token;
         }

        public void UpdateStatus(string newStatus)
        {
           // The Pownce API does not support posting yet. This was a workaround that I found and hoped it would work, 
           // but it does not. I get a server error - 500

           string pownceNotesPath = "http://pownce.com/api/notes/for/" + Username + "/";

           string pownceToken = GetPownceToken(Username, Password);
           string pownceNonce = CreatePownceNonce();
           string pownceTimestamp = GetPownceTimestamp();
           string pownceDigest = GetPownceDigest(pownceToken, pownceNonce, pownceTimestamp);
           string pownceAuth = GetPownceAuthString(pownceDigest, pownceNonce, pownceTimestamp);

           string result = string.Empty;
           HttpWebRequest webRequest = null;
           WebResponse webResponse = null;
           try {
              // note-to : all or public
              string content = "auth=" + HttpUtility.UrlEncode(pownceAuth) +"&note-type=message&note-to=all&note-body=" +
                                 HttpUtility.UrlEncode(newStatus);

              UTF8Encoding encoding = new UTF8Encoding();
              byte[] bytes = encoding.GetBytes(content);

              webRequest = (HttpWebRequest)WebRequest.Create(pownceNotesPath);
              webRequest.Method = "POST";
              webRequest.ServicePoint.Expect100Continue = false;
              webRequest.KeepAlive = false;

              webRequest.ContentType = "application/x-www-urlencoded";
              webRequest.Accept = "application/xml";

              Stream requestStream = webRequest.GetRequestStream();
              requestStream.Write(bytes, 0, bytes.Length);
              requestStream.Close();

              webResponse = webRequest.GetResponse();

              using (StreamReader streamReader = new StreamReader(webResponse.GetResponseStream())) {
                 result = streamReader.ReadToEnd();
                 streamReader.Close();
              }
           } catch (WebException webException) {
              throw webException;
           } catch (Exception exception) {
              throw exception;
           } finally {
              try {
                 if (webRequest != null) {
                    webRequest.GetRequestStream().Close();
                 }
                 if (webResponse != null) {
                    webResponse.GetResponseStream().Close();
                 }
              } catch {

              }
           }
        }

       private static NetworkCredential GetCredentials(string username, string password) {
          return new NetworkCredential(username, password);
       }       
 
        #endregion

        #region Properties

        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }

        public string Username
        {
            get { return _username; }
            set { _username = value; }
        }

        public User CurrentUser
        {
            get
            {
                if (_currentUser == null)
                {
                    //LoadCurrentUser();
                }
                return _currentUser; 
            }
            set { _currentUser = value; }
        }

        private ApiType _pownceApi = ApiType.XML;

        /// <summary>
        /// The Twitter API to use.  Default is XML.
        /// </summary>
        public ApiType PownceApi
        {
            get { return _pownceApi; }
            set { _pownceApi = value; }
        }

        private string FileExtension
        {
            get
            {
                string rtn = string.Empty;
                switch (PownceApi)
                {
                    case ApiType.XML:
                        rtn = "xml";
                        break;
                    case ApiType.JSON:
                    default:
                        rtn = "json";
                        break;
                }
                return rtn;
            }
        }
	
        #endregion
    }
}

